package cn.ztydata.teachingsystem.heaven.dao.redis;

import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisListCommands;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * 章节子节点->redis类
 * Created by chenxin on 2014/12/19.
 */
@Repository
public class ChapterRelationDao extends BaseRedisDao {
    /**
     * 保存子节点ID
     *
     * @author chenxin
     * @since 2014/12/19
     */
    public void saveSonNode(final long nodeId, final long sonId) {
        //获取list操作
        ListOperations<String, Long> listOperations = redisTemplate.opsForList();

        listOperations.rightPush(KeyUtils.chapterSon(nodeId), sonId);
    }

    /**
     * 判断是否存在子节点
     *
     * @author chenxin
     * @since 2014/12/19
     */
    public boolean isEmpty(final long nodeId) {
        //获取list操作
        ListOperations<String, Long> listOperations = redisTemplate.opsForList();

        logger.debug("判断是否存在子节点");
        return listOperations.size(KeyUtils.chapterSon(nodeId)) == 0;
    }

    /**
     * 删除子节点
     *
     * @author chenxin
     * @since 2014/12/19
     */
    public boolean deleteSonNode(final long nodeId, final long sonId) {
        //获取list操作
        ListOperations<String, Long> listOperations = redisTemplate.opsForList();

        logger.debug("删除子节点");
        return listOperations.remove(KeyUtils.chapterSon(nodeId), 0, sonId) > 0;
    }

    /**
     * 更新子节点（拖拽节点到目标节点内）
     *
     * @author chenxin
     * @since 2014/12/22
     */
    public Boolean updateSonNode(final long draggedId, final long parentId, final long dependedId) {
        SessionCallback<Boolean> sessionCallback = new SessionCallback<Boolean>() {
            @Override
            public Boolean execute(RedisOperations operations) throws DataAccessException {
                operations.multi();

                //获取List操作
                ListOperations<String, Long> listOperations = operations.opsForList();

                //在参照节点下顺序插入节点
                listOperations.rightPush(KeyUtils.chapterSon(dependedId), draggedId);
                //删除被拖拽节点在原来父节点下的关系
                listOperations.remove(KeyUtils.chapterSon(parentId), 0, draggedId);

                operations.exec();
                return true;
            }
        };

        logger.debug("更新子节点结果");
        return (Boolean) redisTemplate.execute(sessionCallback);
    }

    /**
     * 更新子节点（拖拽节点到目标节点之前或之后）
     *
     * @author chenxin
     * @since 2014/12/22
     */
    public Boolean updateSonNode(final long draggedId, final long draggedPid, final long dependedId, final long dependedPid,
                                 final int type) {
        final RedisListCommands.Position position;
        if (type == 1) {
            logger.debug("如果:type==1");
            position = RedisListCommands.Position.BEFORE;
        }
        else if (type == 2) {
            logger.debug("如果:type==2");
            position = RedisListCommands.Position.AFTER;
        }
        else {
            logger.debug("默认返回false");
            return false;
        }

        final byte[] draggedIdSerialized = redisTemplate.getValueSerializer().serialize(draggedId);
        final byte[] dependedIdSerialized = redisTemplate.getValueSerializer().serialize(dependedId);
        final byte[] draggedPidKey = redisTemplate.getKeySerializer().serialize(KeyUtils.chapterSon(draggedPid));
        final byte[] dependedPidKey = redisTemplate.getKeySerializer().serialize(KeyUtils.chapterSon(dependedPid));

        RedisCallback<Boolean> redisCallback = new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                connection.multi();

                //删除被拖拽节点在原来父节点下的关系
                connection.lRem(draggedPidKey, 0, draggedIdSerialized);

                //在参照节点之前或之后插入拖拽节点
                connection.lInsert(dependedPidKey, position, dependedIdSerialized, draggedIdSerialized);

                connection.exec();
                return true;
            }
        };

        logger.debug("更新子节点结果");
        return (Boolean) redisTemplate.execute(redisCallback);
    }

    /**
     * 获取节点的子节点ID
     *
     * @author chenxin
     * @since 2014/12/22
     */
    public List<Long> getSonNodes(final long nodeId) {
        //获取list操作
        ListOperations<String, Long> listOperations = redisTemplate.opsForList();

        logger.debug("获取节点的子节点ID集合");
        return listOperations.range(KeyUtils.chapterSon(nodeId), 0, -1);
    }
}
